/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.section;

import org.eclipse.core.runtime.Assert;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Operation;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.preference.ClassDiagramCommonPreferenceConstants;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.umlutils.ICustomAppearence;

/**
 * Section for operation Appearance (in class or interface nodes, for example)
 */
public class OperationAppearanceSection extends PropertyViewSection {

	private static final int PREFERED_GROUP_WIDTH = 100;

	/** graph element on which properties are displayed */
	private GraphElement graphElement;

	/** Check boxes for operation */
	private Button displVisibility, displName, displModifiers;

	/** Check Boxes for Return parameter */
	private Button displRTType, displRTMultiplicity;

	/** Check Boxes for parameters */
	private Button  displParameterDirection, displParameterName, displParameterType, displParameterMultiplicity, displParameterDefault, displParameterModifiers;

	/** Various group that contains check boxes */
	protected Group operationGroup, returnParameterGroup, parameterGroup;

	/** Buttons listeners */
	private SelectionListener displVisibilityListener, displNameListener, displModifiersListener;

	/** parameter listeners */
	private SelectionListener displParameterDirectionListener, displParameterNameListener, displParameterTypeListener, displParameterMultiplicityListener, displParameterDefaultListener, displParameterModifiersListener;

	/** return parameter listeners */
	private SelectionListener displRTTypeListener, displRTMultiplicityListener;


	/**
	 * 
	 * 
	 * @param tabbedPropertySheetPage 
	 * @param parent 
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		Composite composite = getWidgetFactory().createFlatFormComposite(parent);
		createOperationGroup(composite);
		createReturnParameterGroup(composite);
		createParametersGroup(composite);
	}

	/**
	 * Create the group 
	 * @param composite
	 */
	private void createOperationGroup(Composite composite) {
		// create group
		operationGroup = getWidgetFactory().createGroup(composite, "Operation");
		FormLayout layout = new FormLayout();
		operationGroup.setLayout(layout);
		FormData data;

		// create check buttons in this group
		displVisibility = getWidgetFactory().createButton(operationGroup, "Visibility", SWT.CHECK);
		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(0, 0);
		displVisibility.setLayoutData(data);
		displVisibility.addSelectionListener(displVisibilityListener = new AppearenceSelectionListener(ICustomAppearence.DISP_VISIBILITY));

		displName = getWidgetFactory().createButton(operationGroup, "Name", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displVisibility, 0);
		data.left = new FormAttachment(0, 0);
		displName.setLayoutData(data);
		displName.addSelectionListener(displNameListener = new AppearenceSelectionListener(ICustomAppearence.DISP_NAME));

		displModifiers = getWidgetFactory().createButton(operationGroup, "Modifiers", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displName, 0);
		data.left = new FormAttachment(0, 0);
		displModifiers.setLayoutData(data);
		displModifiers.addSelectionListener(displModifiersListener = new AppearenceSelectionListener(ICustomAppearence.DISP_MOFIFIERS));


		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(0, 0);
		data.width = Math.max(PREFERED_GROUP_WIDTH, displVisibility.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
		operationGroup.setLayoutData(data);
	}

	/**
	 * Create the group for return parameter's appearance
	 * @param composite the parent composite for the group 
	 */
	private void createReturnParameterGroup(Composite composite) {
		// create group
		returnParameterGroup = getWidgetFactory().createGroup(composite, "Return Parameter");
		FormLayout layout = new FormLayout();
		returnParameterGroup.setLayout(layout);
		FormData data;

		displRTType = getWidgetFactory().createButton(returnParameterGroup, "Type", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(0, 0);
		data.left = new FormAttachment(0, 0);
		displRTType.setLayoutData(data);
		displRTType.addSelectionListener(displRTTypeListener = new AppearenceSelectionListener(ICustomAppearence.DISP_RT_TYPE));

		displRTMultiplicity = getWidgetFactory().createButton(returnParameterGroup, "Multiplicity", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displRTType, 0);
		data.left = new FormAttachment(0, 0);
		displRTMultiplicity.setLayoutData(data);
		displRTMultiplicity.addSelectionListener(displRTMultiplicityListener = new AppearenceSelectionListener(ICustomAppearence.DISP_RT_MULTIPLICITY));

		data = new FormData();
		data.left = new FormAttachment(operationGroup, 0);
		data.top = new FormAttachment(0, 0);
		data.width = Math.max(PREFERED_GROUP_WIDTH, displRTMultiplicity.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
		returnParameterGroup.setLayoutData(data);
	}

	/**
	 * Create the group for parameters' appearance
	 * @param composite the parent composite for the group 
	 */
	private void createParametersGroup(Composite composite) {
		// create group
		parameterGroup = getWidgetFactory().createGroup(composite, "Parameters");
		FormLayout layout = new FormLayout();
		parameterGroup.setLayout(layout);
		FormData data;

		displParameterDirection = getWidgetFactory().createButton(parameterGroup, "Direction", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(0, 0);
		data.left = new FormAttachment(0, 0);
		displParameterDirection.setLayoutData(data);
		displParameterDirection.addSelectionListener(displParameterDirectionListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_DIRECTION));

		displParameterName = getWidgetFactory().createButton(parameterGroup, "Name", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displParameterDirection, 0);
		data.left = new FormAttachment(0, 0);
		displParameterName.setLayoutData(data);
		displParameterName.addSelectionListener(displParameterNameListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_NAME));

		displParameterType = getWidgetFactory().createButton(parameterGroup, "Type", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displParameterName, 0);
		data.left = new FormAttachment(0, 0);
		displParameterType.setLayoutData(data);
		displParameterType.addSelectionListener(displParameterTypeListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_TYPE));

		displParameterMultiplicity = getWidgetFactory().createButton(parameterGroup, "Multiplicity", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displParameterType, 0);
		data.left = new FormAttachment(0, 0);
		displParameterMultiplicity.setLayoutData(data);
		displParameterMultiplicity.addSelectionListener(displParameterMultiplicityListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_MULTIPLICITY));

		displParameterDefault = getWidgetFactory().createButton(parameterGroup, "Default", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displParameterMultiplicity, 0);
		data.left = new FormAttachment(0, 0);
		displParameterDefault.setLayoutData(data);
		displParameterDefault.addSelectionListener(displParameterDefaultListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_DEFAULT));

		displParameterModifiers = getWidgetFactory().createButton(parameterGroup, "Modifiers", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(displParameterDefault, 0);
		data.left = new FormAttachment(0, 0);
		displParameterModifiers.setLayoutData(data);
		displParameterModifiers.addSelectionListener(displParameterModifiersListener = new AppearenceSelectionListener(ICustomAppearence.DISP_PARAMETER_MODIFIERS));

		data = new FormData();
		data.left = new FormAttachment(returnParameterGroup, 0);
		data.top = new FormAttachment(0, 0);
		data.width = Math.max(PREFERED_GROUP_WIDTH, displParameterMultiplicity.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
		parameterGroup.setLayoutData(data);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
	 */
	@Override
	public void refresh() {
		if(isButtonValid(displVisibility)){
			// get Property associated to this element
//			com.cea.papyrus.diagraminterchange2.di2.Property prop = graphElement.getProperty(ICustomAppearence.CUSTOM_APPEARENCE_KEY);

//			if(prop == null) {
//			// creates a default one
//			prop = Di2Factory.eINSTANCE.createProperty();
//			graphElement.getProperty().add(prop);
//			prop.setKey(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
//			prop.setValue(""+ICustomAppearence.DEFAULT_UML_OPERATION);
//			}

//			int value = Integer.parseInt(prop.getValue());

			IPreferenceStore store = PapyrusPlugin.getDefault().getPreferenceStore();
			int style = 0;

			// get properties on graph node for property: custom display
			com.cea.papyrus.diagraminterchange2.di2.Property prop = graphElement.getProperty(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
			String value = "";
			if(prop == null) {
				// default value 
				style = loadPreferenceStyle(store);
			} else {
				value = prop.getValue();
				if(value != null) {
					try {
						style = Integer.parseInt(value);
					} catch (NumberFormatException e) {
						Debug.log(e);
					}
				}
			}

			if(this.getElement() instanceof Operation) {
				displVisibility.setSelection((style & ICustomAppearence.DISP_VISIBILITY) != 0);
				displName.setSelection((style & ICustomAppearence.DISP_NAME) != 0);
				displModifiers.setSelection((style & ICustomAppearence.DISP_MOFIFIERS) != 0);

				displParameterDirection.setSelection((style & ICustomAppearence.DISP_PARAMETER_DIRECTION) != 0);
				displParameterName.setSelection((style & ICustomAppearence.DISP_PARAMETER_NAME) != 0);
				displParameterType.setSelection((style & ICustomAppearence.DISP_PARAMETER_TYPE) != 0);
				displParameterModifiers.setSelection((style & ICustomAppearence.DISP_PARAMETER_MODIFIERS) != 0);
				displParameterDefault.setSelection((style & ICustomAppearence.DISP_PARAMETER_DEFAULT) != 0);
				displParameterMultiplicity.setSelection((style & ICustomAppearence.DISP_PARAMETER_MULTIPLICITY) != 0);

				displRTType.setSelection((style & ICustomAppearence.DISP_RT_TYPE) != 0);
				displRTMultiplicity.setSelection((style & ICustomAppearence.DISP_RT_MULTIPLICITY) != 0);
			}
		}
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.properties.tabbed.PropertyViewSection#setInput(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
	 */
	public void setInput(IWorkbenchPart part, ISelection selection) {
		super.setInput(part, selection);
		Assert.isTrue(selection instanceof IStructuredSelection);
		Object input = ((IStructuredSelection) selection).getFirstElement();

		if(input instanceof AbstractGraphicalEditPart) {
			graphElement = ((GraphElement)((AbstractGraphicalEditPart) input).getModel());
		} else {
			graphElement = null;
		}
		refresh();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.properties.tabbed.PropertyViewSection#dispose()
	 */
	@Override
	public void dispose(){
		// operation button disposal
		if(isButtonValid(displVisibility)) {
			displVisibility.removeSelectionListener(displVisibilityListener);
		}
		if(isButtonValid(displName)) {
			displName.removeSelectionListener(displNameListener);
		}
		if(isButtonValid(displModifiers)) {
			displModifiers.removeSelectionListener(displModifiersListener);
		}

		// parameter disposal	
		if(isButtonValid(displParameterDirection)) {
			displParameterDirection.removeSelectionListener(displParameterDirectionListener);
		}
		if(isButtonValid(displParameterName)) {
			displParameterName.removeSelectionListener(displParameterNameListener);
		}
		if(isButtonValid(displParameterType)) {
			displParameterType.removeSelectionListener(displParameterTypeListener);
		}
		if(isButtonValid(displParameterMultiplicity)) {
			displParameterMultiplicity.removeSelectionListener(displParameterMultiplicityListener);
		}
		if(isButtonValid(displParameterDefault)) {
			displParameterDefault.removeSelectionListener(displParameterDefaultListener);
		}
		if(isButtonValid(displParameterModifiers)) {
			displParameterModifiers.removeSelectionListener(displParameterModifiersListener);
		}

		// return parameter disposal
		if(isButtonValid(displRTType)) {
			displRTType.removeSelectionListener(displRTTypeListener);
		}
		if(isButtonValid(displRTMultiplicity)) {
			displRTMultiplicity.removeSelectionListener(displRTMultiplicityListener);
		}
		super.dispose();
	}

	/**
	 * Returns default display from preference store
	 * @param store the preference store
	 * @return default display from preference store
	 */
	private int loadPreferenceStyle(IPreferenceStore store) {
		int style = 0;

		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationNameAppearance(store)){
			style = style | ICustomAppearence.DISP_NAME;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationVisibilityAppearance(store)){
			style = style | ICustomAppearence.DISP_VISIBILITY;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationModifiersAppearance(store)){
			style = style | ICustomAppearence.DISP_MOFIFIERS;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationRTTypeAppearance(store)){
			style = style | ICustomAppearence.DISP_RT_TYPE;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationRTMultiplicityAppearance(store)){
			style = style | ICustomAppearence.DISP_RT_MULTIPLICITY;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterDirectionAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_DIRECTION;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterNameAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_NAME;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterTypeAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_TYPE;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterMultiplicityAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_MULTIPLICITY;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterDefaultValueAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_DEFAULT;
		}
		if (ClassDiagramCommonPreferenceConstants.getPreferenceOperationParameterModifiersAppearance(store)){
			style = style | ICustomAppearence.DISP_PARAMETER_MODIFIERS;
		}
		// for old models, with only DISP_PARAMETERS
		return style;
	}

	/**
	 * 
	 */
	private class AppearenceSelectionListener implements SelectionListener {

		/**
		 * the constant which refers the element to display or not.
		 */
		private int style;

		/**
		 * Default Constructor.
		 * 
		 * @param style 
		 */
		public AppearenceSelectionListener(int style) {
			this.style = style;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void widgetDefaultSelected(SelectionEvent e) {

		}

		/* (non-Javadoc)
		 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		/**
		 * 
		 * 
		 * @param e 
		 */
		public void widgetSelected(SelectionEvent e) {
			Button button = (Button)e.getSource();
			boolean isSelected = button.getSelection();

			if(graphElement == null) {
				return;
			}
			
			// default value has changed: set custom appearance property
			com.cea.papyrus.diagraminterchange2.di2.Property prop = graphElement.getProperty(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
			if(prop == null) {
				prop = Di2Factory.eINSTANCE.createProperty();
				graphElement.getProperty().add(prop);
				prop.setKey(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
				prop.setValue(""+loadPreferenceStyle(PapyrusPlugin.getDefault().getPreferenceStore()));
			}
			int value = Integer.parseInt(prop.getValue());

			if(isSelected) {
				if((value & style) == 0) {
					prop.setValue(""+(value | style));
				}
			} else {
				if((value & style) != 0) {
					prop.setValue(""+(value & ~style));
				}
			}
			forceToSave();
			refresh();
		}
	}

	/**
	 * returns <code>true</code> if the button is valid, i.e. not disposed and not <code>null</code>
	 * @param button the button to check
	 * @return <code>true</code> if the button is valid, i.e. not disposed and not <code>null</code>
	 */
	protected boolean isButtonValid(Button button) {
		return (button!=null && !button.isDisposed());
	}
}

